package gnu.io;

import java.util.*;
import java.io.*;

public class CommPortIdentifier
{
    public static final int PORT_SERIAL = 1;
    public static final int PORT_PARALLEL = 2;
    public static final int PORT_I2C = 3;
    public static final int PORT_RS485 = 4;
    public static final int PORT_RAW = 5;
    private String PortName;
    private boolean Available;
    private String Owner;
    private CommPort commport;
    private CommDriver RXTXDriver;
    static CommPortIdentifier CommPortIndex;
    CommPortIdentifier next;
    private int PortType;
    private static final boolean debug = false;
    static Object Sync;
    Vector ownershipListener;
    private boolean HideOwnerEvents;
    
    CommPortIdentifier(final String portName, final CommPort commport, final int portType, final CommDriver rxtxDriver) {
        this.Available = true;
        this.PortName = portName;
        this.commport = commport;
        this.PortType = portType;
        this.next = null;
        this.RXTXDriver = rxtxDriver;
    }
    
    public static void addPortName(final String s, final int n, final CommDriver commDriver) {
        AddIdentifierToList(new CommPortIdentifier(s, null, n, commDriver));
    }
    
    private static void AddIdentifierToList(final CommPortIdentifier commPortIdentifier) {
        synchronized (CommPortIdentifier.Sync) {
            if (CommPortIdentifier.CommPortIndex == null) {
                CommPortIdentifier.CommPortIndex = commPortIdentifier;
            }
            else {
                CommPortIdentifier commPortIdentifier2;
                for (commPortIdentifier2 = CommPortIdentifier.CommPortIndex; commPortIdentifier2.next != null; commPortIdentifier2 = commPortIdentifier2.next) {}
                commPortIdentifier2.next = commPortIdentifier;
            }
        }
    }
    
    public void addPortOwnershipListener(final CommPortOwnershipListener commPortOwnershipListener) {
        if (this.ownershipListener == null) {
            this.ownershipListener = new Vector();
        }
        if (!this.ownershipListener.contains(commPortOwnershipListener)) {
            this.ownershipListener.addElement(commPortOwnershipListener);
        }
    }
    
    public String getCurrentOwner() {
        return this.Owner;
    }
    
    public String getName() {
        return this.PortName;
    }
    
    public static CommPortIdentifier getPortIdentifier(final String s) throws NoSuchPortException {
        CommPortIdentifier commPortIdentifier;
        synchronized (CommPortIdentifier.Sync) {
            for (commPortIdentifier = CommPortIdentifier.CommPortIndex; commPortIdentifier != null && !commPortIdentifier.PortName.equals(s); commPortIdentifier = commPortIdentifier.next) {}
            if (commPortIdentifier == null) {
                getPortIdentifiers();
                for (commPortIdentifier = CommPortIdentifier.CommPortIndex; commPortIdentifier != null && !commPortIdentifier.PortName.equals(s); commPortIdentifier = commPortIdentifier.next) {}
            }
        }
        if (commPortIdentifier != null) {
            return commPortIdentifier;
        }
        throw new NoSuchPortException();
    }
    
    public static CommPortIdentifier getPortIdentifier(final CommPort commPort) throws NoSuchPortException {
        CommPortIdentifier commPortIdentifier;
        synchronized (CommPortIdentifier.Sync) {
            for (commPortIdentifier = CommPortIdentifier.CommPortIndex; commPortIdentifier != null && commPortIdentifier.commport != commPort; commPortIdentifier = commPortIdentifier.next) {}
        }
        if (commPortIdentifier != null) {
            return commPortIdentifier;
        }
        throw new NoSuchPortException();
    }
    
    public static Enumeration getPortIdentifiers() {
        synchronized (CommPortIdentifier.Sync) {
            final HashMap<String, CommPortIdentifier> hashMap = new HashMap<String, CommPortIdentifier>();
            for (CommPortIdentifier commPortIdentifier = CommPortIdentifier.CommPortIndex; commPortIdentifier != null; commPortIdentifier = commPortIdentifier.next) {
                hashMap.put(commPortIdentifier.PortName, commPortIdentifier);
            }
            CommPortIdentifier.CommPortIndex = null;
            try {
                ((CommDriver)Class.forName("gnu.io.RXTXCommDriver").newInstance()).initialize();
                CommPortIdentifier commPortIdentifier2 = CommPortIdentifier.CommPortIndex;
                CommPortIdentifier commPortIdentifier3 = null;
                while (commPortIdentifier2 != null) {
                    final CommPortIdentifier commPortIdentifier4 = hashMap.get(commPortIdentifier2.PortName);
                    if (commPortIdentifier4 != null && commPortIdentifier4.PortType == commPortIdentifier2.PortType) {
                        commPortIdentifier4.RXTXDriver = commPortIdentifier2.RXTXDriver;
                        commPortIdentifier4.next = commPortIdentifier2.next;
                        if (commPortIdentifier3 == null) {
                            CommPortIdentifier.CommPortIndex = commPortIdentifier4;
                        }
                        else {
                            commPortIdentifier3.next = commPortIdentifier4;
                        }
                        commPortIdentifier3 = commPortIdentifier4;
                    }
                    else {
                        commPortIdentifier3 = commPortIdentifier2;
                    }
                    commPortIdentifier2 = commPortIdentifier2.next;
                }
            }
            catch (Throwable t) {
                System.err.println(t + " thrown while loading " + "gnu.io.RXTXCommDriver");
                System.err.flush();
            }
        }
        return new CommPortEnumerator();
    }
    
    public int getPortType() {
        return this.PortType;
    }
    
    public synchronized boolean isCurrentlyOwned() {
        return !this.Available;
    }
    
    public synchronized CommPort open(final FileDescriptor fileDescriptor) throws UnsupportedCommOperationException {
        throw new UnsupportedCommOperationException();
    }
    
    private native String native_psmisc_report_owner(final String p0);
    
    public CommPort open(final String s, final int n) throws PortInUseException {
        boolean b;
        synchronized (this) {
            b = this.Available;
            if (b) {
                this.Available = false;
                this.Owner = s;
            }
        }
        if (!b) {
            final long n2 = System.currentTimeMillis() + n;
            this.fireOwnershipEvent(3);
            synchronized (this) {
                long currentTimeMillis;
                while (!this.Available && (currentTimeMillis = System.currentTimeMillis()) < n2) {
                    try {
                        this.wait(n2 - currentTimeMillis);
                        continue;
                    }
                    catch (InterruptedException ex) {
                        Thread.currentThread().interrupt();
                    }
                    break;
                }
                b = this.Available;
                if (b) {
                    this.Available = false;
                    this.Owner = s;
                }
            }
        }
        if (!b) {
            throw new PortInUseException(this.getCurrentOwner());
        }
        try {
            if (this.commport == null) {
                this.commport = this.RXTXDriver.getCommPort(this.PortName, this.PortType);
            }
            if (this.commport != null) {
                this.fireOwnershipEvent(1);
                return this.commport;
            }
            throw new PortInUseException(this.native_psmisc_report_owner(this.PortName));
        }
        finally {
            if (this.commport == null) {
                synchronized (this) {
                    this.Available = true;
                    this.Owner = null;
                }
            }
        }
    }
    
    public void removePortOwnershipListener(final CommPortOwnershipListener commPortOwnershipListener) {
        if (this.ownershipListener != null) {
            this.ownershipListener.removeElement(commPortOwnershipListener);
        }
    }
    
    void internalClosePort() {
        synchronized (this) {
            this.Owner = null;
            this.Available = true;
            this.commport = null;
            this.notifyAll();
        }
        this.fireOwnershipEvent(2);
    }
    
    void fireOwnershipEvent(final int n) {
        if (this.ownershipListener != null) {
            final Enumeration<CommPortOwnershipListener> elements = this.ownershipListener.elements();
            while (elements.hasMoreElements()) {
                elements.nextElement().ownershipChange(n);
            }
        }
    }
    
    static {
        CommPortIdentifier.Sync = new Object();
        try {
            ((CommDriver)Class.forName("gnu.io.RXTXCommDriver").newInstance()).initialize();
        }
        catch (Throwable t) {
            System.err.println(t + " thrown while loading " + "gnu.io.RXTXCommDriver");
        }
        if (System.getProperty("os.name").toLowerCase().indexOf("linux") == -1) {}
        System.load(System.getProperty("user.dir")+File.separator+"rxtxSerial.dll");
    }
}
